﻿using System;
using System.Drawing;
using System.IO;
using System.IO.Ports;//串口模块
using System.Text;
using System.Windows.Forms;

namespace MainSender
{
    //解决线程访问问题
    public delegate void SerialPortEventHandler(Object sender, SerialPortEventArgs e);//定义委托

    public partial class SerialDebug : Form
    {
        private string FilePath = null;//文件路径

        private object thisLock = new object();//锁住线程

        public event SerialPortEventHandler comReceiveDataEvent = null;//串口接收数据响应事件

        private static int sendCount = 0;//发送数据量
        private static int receCount = 0;//接收数据量

        public SerialDebug()
        {
            InitializeComponent();
            InitializeSerialSet();
        }

        /// <summary>
        /// 串口初始化
        /// </summary>
        public void InitializeSerialSet()
        {
            InitializePorts();//设置串口号
            comboBox_BaudRate.Text = comboBox_BaudRate.Items[6].ToString();//设置波特率
            comboBox_Check.Text = comboBox_Check.Items[0].ToString();//设置校验位
            comboBox_Data.Text = comboBox_Data.Items[0].ToString();//设置数据位
            comboBox_Stop.Text = comboBox_Stop.Items[0].ToString();//设置停止位

        }

        /// <summary>
        /// 可用串口扫描和显示
        /// </summary>
        public void InitializePorts()
        {
            comboBox_Serial.Items.Clear();//清空串口选择下拉框

            string[] arraysPostsNames = SerialPort.GetPortNames();//获取所有可用串口

            if (arraysPostsNames.Length > 0)
            {
                for (int i = 0; i < arraysPostsNames.Length; i++)
                {
                    comboBox_Serial.Items.Add(arraysPostsNames[i]);//将所有可用串口加载到串口选择下拉框中
                }
                comboBox_Serial.Text = arraysPostsNames[0];//默认选择第一个串口
                comboBox_Serial.Enabled = true;//使能串口选择下拉框

                toolStripStatus_Port.Text = "串口号：" + comboBox_Serial.Text;//设置状态栏
                toolStripStatus_Port.ForeColor = Color.Black;//设置为黑色
            }
            else
            {
                comboBox_Serial.Text = "None";//提示没有可用串口
                comboBox_Serial.Enabled = false;//禁用串口选择下拉框

                toolStripStatus_Port.Text = "无可用串口";//设置状态栏
                toolStripStatus_Port.ForeColor = Color.Red;//设置为红色
            }
        }

        /// <summary>
        /// 串口接收的数据处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPortMonitor_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            ReceiveData();
        }

        private void SerialDebug_Load(object sender, EventArgs e)
        {
            comReceiveDataEvent += new SerialPortEventHandler(ComReceiveDataEvent);//订阅事件
            toolStripStatus_Time.Text = "时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");//显示当前时间
        }

        public void ComReceiveDataEvent(Object sender, SerialPortEventArgs e)
        {

            if (this.InvokeRequired)
            {
                try
                {
                    Invoke(new Action<Object, SerialPortEventArgs>(ComReceiveDataEvent), sender, e);
                }
                catch (Exception)
                {

                }
                return;
            }


            if (richTextBox_Receive.Text.Length > 0)
            {
                richTextBox_Receive.AppendText(" ");//中间使用 隔开，也可以使用-隔开
            }
            richTextBox_Receive.AppendText(System.Text.Encoding.Default.GetString(e.receivedBytes));

            //更新状态栏
            receCount += e.receivedBytes.Length;
            toolStripStatus_recestatus.Text = "收到数据: " + receCount.ToString();
        }

        /// <summary>
        /// 串口选择框改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Select_Ports_Change(object sender, EventArgs e)
        {
            toolStripStatus_Port.Text = "串口号：" + comboBox_Serial.Text;//设置状态栏
            toolStripStatus_Port.ForeColor = Color.Black;//设置为黑色
        }

        /// <summary>
        /// 更新状态栏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Update_StatusTime(object sender, EventArgs e)
        {
            
            toolStripStatus_Time.Text = "时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");//显示当前时间
        }

        /// <summary>
        /// 保存文件加载方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SaveData_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveDataSend = new SaveFileDialog();
            saveDataSend.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);//获取文件路径
            saveDataSend.Filter = "*.txt|txt file";//文本文件
            saveDataSend.DefaultExt = ".txt";//默认文件的形式
            saveDataSend.FileName = "SendData.txt";//文件默认名

            if (saveDataSend.ShowDialog() == DialogResult.OK)//显示文件框，并且选择文件
            {
                FilePath = saveDataSend.FileName;//获取文件名
                // 参数1：写入文件的文件名；参数2：写入文件的内容
                try
                {
                    System.IO.File.WriteAllText(FilePath, richTextBox_Send.Text);//向文件中写入内容
                }
                catch
                {
                    MessageBox.Show("保存文件失败", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }

        /// <summary>
        /// 选择发送文件响应函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox_Filepath_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.Multiselect = false;//是否可以选择多个文件
            fileDialog.Title = "请选择文件";//标题
            fileDialog.Filter = "所有文件(*.*)|*.*";//显示所有文件
            if (fileDialog.ShowDialog() == DialogResult.OK)//打开文件选择框
            {
                FilePath = fileDialog.FileName;//绝对路径
                textBox_Filepath.Text = FilePath;//在窗口中显示文件路径
            }
            checkBox_Sendfile.Checked = true;//设置发送文件框选项状态
            ReadFile(FilePath);//将文件内容显示在发送框当中
        }

        /// <summary>
        /// 将文件内容显示在发送数据显示框中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ReadFile(string filepath)
        {
            try
            {
                richTextBox_Send.Text = "";//清空显示框

                StreamReader sr = new StreamReader(filepath, Encoding.Default);
                string content;
                while ((content = sr.ReadLine()) != null)//按行读取显示在发送数据框中
                {
                    richTextBox_Send.Text += (content.ToString() + "\r\n");//ReadLine默认不会读取换行符
                }
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// 清除发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_ClcSendData_Click(object sender, EventArgs e)
        {
            richTextBox_Send.Text = "";//清空显示框
            sendCount = 0;
            toolStripStatus_sendstatus.Text = "发送数据：" + sendCount.ToString();
        }

        /// <summary>
        /// 清除接收数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_ClcReceData_Click(object sender, EventArgs e)
        {
            richTextBox_Receive.Text = "";//清空接收数据
            receCount = 0;
            toolStripStatus_recestatus.Text = "收到数据：" + receCount.ToString();
        }

        /// <summary>
        /// 发送数据按键点击响应函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_SendData_Click(object sender, EventArgs e)
        {
            string senddata = richTextBox_Send.Text;
            byte[] data = System.Text.Encoding.Default.GetBytes(senddata);//将发送的数据转化为字节数组
            SendData(data);//发送数据
            sendCount += senddata.Length;
            toolStripStatus_sendstatus.Text = "发送数据：" + sendCount.ToString();
        }

        /// <summary>
        /// 保存发送数据，保存发送数据菜单响应函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_ReceData_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveDataSend = new SaveFileDialog();
            saveDataSend.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);//获取文件路径
            saveDataSend.Filter = "*.txt|txt file";//文本文件
            saveDataSend.DefaultExt = ".txt";//默认文件的形式
            saveDataSend.FileName = "ReceData.txt";//文件默认名

            if (saveDataSend.ShowDialog() == DialogResult.OK)//显示文件框，并且选择文件
            {
                FilePath = saveDataSend.FileName;//获取文件名
                // 参数1：写入文件的文件名；参数2：写入文件的内容
                try
                {
                    System.IO.File.WriteAllText(FilePath, richTextBox_Receive.Text);//向文件中写入内容
                }
                catch
                {
                    MessageBox.Show("保存文件失败", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

            }
        }

        /// <summary>
        /// 串口状态响应函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_OK_Click(object sender, EventArgs e)
        {
            if (serialPort1 == null)
            {
                return;
            }

            if (serialPort1.IsOpen == false)
            {
                serialPort1.PortName = comboBox_Serial.Text;
                serialPort1.BaudRate = Convert.ToInt32(comboBox_BaudRate.Text);
                serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), comboBox_Check.Text);//强制类型转换
                serialPort1.DataBits = Convert.ToInt32(comboBox_Data.Text);
                serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBox_Stop.Text);
                try
                {
                    serialPort1.Open();

                    comboBox_Serial.Enabled = false;
                    comboBox_BaudRate.Enabled = false;
                    comboBox_Check.Enabled = false;
                    comboBox_Data.Enabled = false;
                    comboBox_Stop.Enabled = false;
                    button_Refresh.Enabled = false;

                    button_SendData.Enabled = true;
                    checkBox_SendData.Enabled = true;
                    textBox_selectTime.Enabled = true;
                    checkBox_Sendfile.Enabled = true;
                    textBox_Filepath.Enabled = true;

                    //打开属性变为关闭属性
                    button_OK.Text = "关闭串口";

                    toolStripStatus_Port.Text = "连接串口:" + comboBox_Serial.Text;
                    toolStripStatus_Port.ForeColor = Color.Green;//设置为绿色

                }
                catch (Exception)
                {
                    toolStripStatus_Port.Text = "连接失败:" + comboBox_Serial.Text;
                    toolStripStatus_Port.ForeColor = Color.Red;//设置为红色
                    MessageBox.Show("串口连接失败！\r\n可能原因：串口被占用", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                serialPort1.Close();//关闭串口

                comboBox_Serial.Enabled = true;
                comboBox_BaudRate.Enabled = true;
                comboBox_Check.Enabled = true;
                comboBox_Data.Enabled = true;
                comboBox_Stop.Enabled = true;
                button_Refresh.Enabled = true;

                button_SendData.Enabled = false;
                checkBox_SendData.Enabled = false;
                textBox_selectTime.Enabled = false;
                checkBox_Sendfile.Enabled = false;
                textBox_Filepath.Enabled = false;

                //打开属性变为关闭属性
                button_OK.Text = "打开串口";
                toolStripStatus_Port.Text = "断开连接:" + comboBox_Serial.Text;
                toolStripStatus_Port.ForeColor = Color.Red;//设置为红色
            }
        }

        /// <summary>
        /// 向串口中发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public bool SendData(byte[] data)
        {
            if (serialPort1 == null)
            {
                return false;
            }
            if (serialPort1.IsOpen == false)
            {
                return false;
            }

            try
            {
                serialPort1.Write(data, 0, data.Length);
            }
            catch (Exception)
            {
                //提示信息
                MessageBox.Show("数据发送失败！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 串口接收数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public bool ReceiveData()
        {
            if (serialPort1 == null)
            {
                return false;
            }
            if (serialPort1.IsOpen == false)
            {
                return false;
            }
            if (serialPort1.BytesToRead <= 0)//串口中没有数据
            {
                return false;
            }

            lock (thisLock)//锁住串口
            {
                int len = serialPort1.BytesToRead;
                byte[] data = new Byte[len];
                try
                {
                    serialPort1.Read(data, 0, len);//读取数据
                }
                catch (Exception)
                {
                    MessageBox.Show("数据接收失败！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return false;
                }

                SerialPortEventArgs args = new SerialPortEventArgs();
                args.receivedBytes = data;
                if (comReceiveDataEvent != null)
                {
                    comReceiveDataEvent.Invoke(this, args);
                }
            }

            return true;
        }

        /// <summary>
        /// 刷新串口参数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_Refresh_Click(object sender, EventArgs e)
        {
            InitializeSerialSet();//刷新串口设置
        }

        /// <summary>
        /// 定时发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerSend_Tick(object sender, EventArgs e)
        {
            if (checkBox_SendData.Checked)
            {
                string datastr = richTextBox_Send.Text;
                if (datastr == "")
                {
                    return;
                }
                timerSend.Interval = int.Parse(textBox_selectTime.Text);//将字符串转化为整型数字
                byte[] data = System.Text.Encoding.Default.GetBytes(datastr);//字符串转化为字节数组
                SendData(data);
                sendCount += datastr.Length;
                toolStripStatus_sendstatus.Text = "发送数据：" + sendCount.ToString();

                button_SendData.Enabled = false;//控件设置
            }
            else
            {
                button_SendData.Enabled = true;
            }
        }

        /// <summary>
        /// 退出菜单
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_Quit_Click(object sender, EventArgs e)
        {
            this.Close();//关闭窗体，然后退出
        }

        /// <summary>
        /// 关于菜单
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_About_Click(object sender, EventArgs e)
        {
            About about = new About();
            about.Show();//显示关于窗体
        }
    }

    public class SerialPortEventArgs : EventArgs
    {
        public byte[] receivedBytes = null;//用来接收串口读取的数据
    }
}